package com.zt.bigdata.practise.javastrategy.chapter4;

import com.zt.bigdata.practise.javastrategy.chapter4.dto.Golfer;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.Comparator.comparing;
import static java.util.Comparator.comparingInt;
import static java.util.Comparator.naturalOrder;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toConcurrentMap;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toSet;

/**
 * 比较器与收集器 Comparator && Collector
 */
public class Chapter4 {
    private static List<String> sampleStrings =
            Arrays.asList("this", "is", "a", "list", "of", "strings");
    private static List<Golfer> golfersBuilder = Arrays.asList(
            new Golfer("Jack", "Nicklaus", 68),
            new Golfer("Tiger", "Woods", 70),
            new Golfer("Tom", "Watson", 70),
            new Golfer("Ty", "Webb", 68),
            new Golfer("Bubba", "Watson", 70));

    public static void main(String[] args) {
        //4.1 利用比较器实现排序
        Collections.sort(sampleStrings);
        sampleStrings.stream()
                .sorted()//生成一个新的流
                .collect(toList());
        sampleStrings.stream()
                .sorted((s1, s2) -> s1.length() - s2.length())
                .collect(toList());
        sampleStrings.stream()
                .sorted(comparingInt(String::length)).collect(toList());
        sampleStrings.stream()
                //根据长度对字符串排序，长度相同则按字母顺序排序
                .sorted(comparing(String::length).thenComparing(naturalOrder()))
                .collect(toList());
        golfersBuilder.stream()
                .sorted(comparingInt(Golfer::getScore)
                        .thenComparing(Golfer::getLast)
                        .thenComparing(Golfer::getFirst)
                ).collect(toList());

        golfersBuilder.stream().collect(toList());
        golfersBuilder.stream().collect(toSet());
        golfersBuilder.stream().collect(Collectors.toCollection(LinkedList::new));
        golfersBuilder.stream().map(Golfer::getFirst).toArray(String[]::new);
        Map<String, Golfer> map = golfersBuilder
                .stream()
                .collect(
                        toMap(
                                golf -> golf.getFirst(),
                                golf -> golf)
                );
        map = golfersBuilder
                .stream()
                .collect(toConcurrentMap(Golfer::getFirst, golfer -> golfer));

        //4.3 将线性集合添加到映射
        map = golfersBuilder
                .stream()
                .collect(toConcurrentMap(Golfer::getFirst, Function.identity()));
        map = golfersBuilder
                .stream()
                .collect(toConcurrentMap(Golfer::getFirst, UnaryOperator.identity()));
        /*
        static <T> Function<T, T> identity() {
        return t -> t;}
        */

        //4.4 对映射排序
        System.out.println("\nNumber of words of each length:");
        try (Stream<String> lines = Files.lines(Paths.get("/usr/share/dict/words"))) {
            Map<Integer, Long> map1 = lines.filter(s -> s.length() > 20)
                    .collect(Collectors.groupingBy(
                            String::length, Collectors.counting()));

            map1.entrySet().stream()
                    .sorted(Map.Entry.comparingByKey(Comparator.reverseOrder()))
                    .forEach(e -> System.out.printf("Length %d: %2d words%n",
                            e.getKey(), e.getValue()));

        } catch (IOException e) {
            e.printStackTrace();
        }

        //4.5 分区与分组
        //根据成绩分组
        Map<Integer, List<Golfer>> groupingByScore = golfersBuilder.stream().collect(
                Collectors.groupingBy(
                        golfer -> golfer.getScore(),
                        Collectors.toList()
                )
        );
        System.out.println(groupingByScore);

        //根据长度排序
        Map<Boolean, List<String>> lengthMap = sampleStrings.stream()
                .collect(
                        Collectors.partitioningBy(x -> x.length() % 2 == 0)
                );
        lengthMap.forEach((key, value) -> System.out.printf("%5s: %s%n", key, value));

        //4.6 下游收集器
        //户希望对 groupingBy 或 partitioningBy 操作返回的集合进行后期处理。
        golfersBuilder.stream().collect(
                Collectors.groupingBy(
                        golfer -> golfer.getScore(),
                        Collectors.toList() //下游收集  将不同分组的数据 手机成list set map 等等
                )
        );
        Map<Boolean, StringBuilder> strMap = sampleStrings.stream()
                .collect(
                        Collectors.partitioningBy(
                                s -> s.length() % 2 == 0,
                                new Collector<String, StringBuilder, StringBuilder>() {
                                    @Override
                                    public Supplier<StringBuilder> supplier() {
                                        return StringBuilder::new;
                                    }

                                    @Override
                                    public BiConsumer<StringBuilder, String> accumulator() {
                                        return (sb, s) -> sb.append(s + " ");
                                    }

                                    @Override
                                    public BinaryOperator<StringBuilder> combiner() {
                                        return (sb1, sb2) -> sb1.append(sb2);
                                    }

                                    @Override
                                    public Function<StringBuilder, StringBuilder> finisher() {
                                        return stringBuilder -> stringBuilder;
                                    }

                                    @Override
                                    public Set<Characteristics> characteristics() {
                                        return new HashSet() {{
                                            add(Characteristics.IDENTITY_FINISH);
                                        }};
                                    }
                                }
                        )
                );
        System.out.println(strMap);

        //4.7 查找最大值和最小值
        golfersBuilder.stream().max(Comparator.comparingLong(Golfer::getScore));
        golfersBuilder.stream().mapToLong(Golfer::getScore).max();
        golfersBuilder.stream().collect(Collectors.maxBy(Comparator.comparingLong(Golfer::getScore)));

        //4.8 创建不可变集合
        Collections.unmodifiableList(Arrays.asList(golfersBuilder));
        Stream.of(golfersBuilder).collect(collectingAndThen(toSet(),
                Collections::unmodifiableSet));
        Collections.unmodifiableMap(new HashMap<String, Integer>() {{
            put("have", 1);
            put("the", 2);
            put("high", 3);
            put("ground", 4);
        }});

        //4.9 实现Collector接口
        Map<Boolean, StringBuilder> stringBuilderMap = sampleStrings.stream()
                .collect(
                        Collectors.partitioningBy(
                                s -> s.length() % 2 == 0,
                                new Collector<String, StringBuilder, StringBuilder>() {
                                    @Override
                                    public Supplier<StringBuilder> supplier() {
                                        return StringBuilder::new;
                                        //使用 Supplier<A> 创建累加器容器(accumulator container)。
                                    }

                                    @Override
                                    public BiConsumer<StringBuilder, String> accumulator() {
                                        return (sb, s) -> sb.append(s + " ");
                                        //使用 BiConsumer<A,T> 为累加器容器添加一个新的数据元素。
                                    }

                                    @Override
                                    public BinaryOperator<StringBuilder> combiner() {
                                        return (sb1, sb2) -> sb1.append(sb2);
                                        //使用 BinaryOperator<A> 合并两个累加器容器。
                                    }

                                    @Override
                                    public Function<StringBuilder, StringBuilder> finisher() {
                                        return stringBuilder -> stringBuilder;
                                        //使用 Function<A,R> 将累加器容器转换为结果容器。
                                    }

                                    @Override
                                    public Set<Characteristics> characteristics() {
                                        return new HashSet() {{
                                            add(Characteristics.IDENTITY_FINISH);
                                            //从枚举值中选择的 Set<Collector.Characteristics>。
                                        }};
                                    }
                                }
                        )
                );

        sampleStrings.stream()
                .collect(
                        Collectors.partitioningBy(
                                s -> s.length() % 2 == 0,
                                Collector.of(
                                        StringBuilder::new,
                                        (stringBuilder, o) -> stringBuilder.append(o),
                                        (stringBuilder, stringBuilder2) -> stringBuilder.append(stringBuilder2),
                                        stringBuilder -> stringBuilder,
                                        Collector.Characteristics.IDENTITY_FINISH
                                )
                        )
                );
    }

}

